#include "stdafx.h"
#include "MessageLoop.h"
#include "Time.h"
#include <mmsystem.h>
#include "Task.h"
#include "WidgetWin.h"

#define WM_USERMESSAGE  (WM_USER + 1)
MessageLoop::MessageLoop()
	: m_isQuit(false)
{
}


MessageLoop::~MessageLoop()
{
}

bool MessageLoop::init()
{
	return true;
}

bool MessageLoop::run()
{
	Time::highResTime(true);
	DWORD dwStart = timeGetTime();

	while (!quit())
	{
		// ATLTRACE("tickcount: %d\r\n", timeGetTime() - dwStart);
		dwStart = timeGetTime();

		processNextWinMessage();

		// process task

		// process delay task
		processDelayWork();
		//

		// wait message
		wait4Work();

	}

	Time::highResTime(false);


	return true;
}

bool MessageLoop::quit()
{
	return m_isQuit;
}

bool MessageLoop::addTask(std::shared_ptr<Task> task)
{
	// TODO
	if (tasks_.size() == 0)
	{
		if (!Time::isHighResTime())
		{
			Time::highResTime(true);
		}
	}

	// ATLTRACE(L"TODO: change algo\r\n");
	bool isAdded = false;
	for (std::list<std::shared_ptr<Task>>::iterator iter = tasks_.begin();
		iter != tasks_.end(); ++iter)
	{
		if (task->getTick() < (*iter)->getTick())
		{
			tasks_.insert(iter, task);
			isAdded = true;
			if (iter == tasks_.begin() && tasks_.size() > 1)
			{
				::PostMessage(WidgetWin::getInstance().getNativeHwnd(), WM_USERMESSAGE, NULL, NULL);
			}
			break;
		}
	}

	if (!isAdded)
	{
		tasks_.push_back(task);
	}
	// tasks_.insert()
	// tasks_.push_back(task);
	// tasks_.sort();
	return true;
}

bool MessageLoop::processNextWinMessage()
{
	// check sent message
	bool has_sent_message = false;
	DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE);
	if (HIWORD(queue_status) & QS_SENDMESSAGE)
	{
		has_sent_message = true;
	}

	// Normal win message
	MSG msg;
	if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
	{
		return processMessage(msg);
	}

	return has_sent_message;
}

bool MessageLoop::processMessage(MSG& msg)
{
	if (WM_QUIT == msg.message)
	{
		m_isQuit = true;
		return false;
	}

	TranslateMessage(&msg);
	DispatchMessage(&msg);

	return true;
}
bool MessageLoop::processDelayWork()
{
	if (tasks_.size() > 0)
	{
		for (std::list<std::shared_ptr<Task>>::iterator iter = tasks_.begin();
			iter != tasks_.end(); )
		{
			if ((*iter)->needRun())
			{
				(*iter)->run(NULL);
				std::list<std::shared_ptr<Task>>::iterator eraseIter = iter;
				++iter;
				tasks_.erase(eraseIter);
			}
			else
			{
				++iter;
			}
		}
	}

/*
	if (tasks_.size() == 0)
	{
		Time::highResTime(false);
	}
*/

	return true;
}



void MessageLoop::wait4Work()
{
	// get delay time & wait massage
	int delayTime = getDelayTaskTime();
	if (delayTime == -1)
	{
	    delayTime = INFINITE;
	}
	DWORD result = 0;
	result = MsgWaitForMultipleObjectsEx(0, NULL, delayTime, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
}

int MessageLoop::getDelayTaskTime()
{
	if (tasks_.size() == 0)
	{
		return -1; // no task.
	}

	std::list<std::shared_ptr<Task>>::iterator task = tasks_.begin();

	TimeTicks tick = (*task)->getTick();
	TimeTicks tickDelta = tick - Time::now();
	return tickDelta.getTick();
}